package com.m1.tzolkin.model.players;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;

import com.m1.tzolkin.model.IStartingWealth;
import com.m1.tzolkin.model.ITZStock;
import com.m1.tzolkin.model.TZStock;
import com.m1.tzolkin.model.TzolkinConstants;
import com.m1.tzolkin.model.buildables.IActionBuilding;
import com.m1.tzolkin.model.buildables.IFarm;
import com.m1.tzolkin.model.buildables.IMonument;
import com.m1.tzolkin.model.exceptions.NotEnoughCornException;
import com.m1.tzolkin.model.log.ILog;
import com.m1.tzolkin.model.util.player.ScorePlayer;

public class TZPlayer extends ScorePlayer implements ITZPlayer, TzolkinConstants {
	
	// ATTRIBUTS
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -8102817005909988495L;
	private final ICornManager cornManager;
	private final Collection<IActionBuilding> actionBuildings;
	private final Collection<IMonument> monuments;
	private final ITZStock amount;
	private int cornTiles;
	private int woodTiles;
	private Collection<IWorker> workersTotal;
	private Collection<IWorker> workersHand;
	private boolean turnTwice;
	private final Collection<IStartingWealth> startingWealths;
	private final PropertyChangeSupport listeners;
	private final boolean isIA;
	private boolean isFirstPlayer;
	
	// CONSTRUCTEUR
	
	public TZPlayer(String s) {
		this(s, false);
	}
	
	public TZPlayer(String s, boolean isIA) {
		super(s);
		this.isIA = isIA;
		cornManager = new CornManager(this);
		actionBuildings = new HashSet<IActionBuilding>();
		monuments = new HashSet<IMonument>();
		amount = new TZStock();
		cornTiles = 0;
		woodTiles = 0;
		turnTwice = true;
		workersTotal = new HashSet<IWorker>();
		workersHand = new HashSet<IWorker>();
		for (int i = 0; i < DEFAULT_WORKERS; ++i) {
			IWorker w = new Worker(this);
			workersTotal.add(w);
			workersHand.add(w);
		}
		startingWealths = new ArrayList<IStartingWealth>();
		listeners = new PropertyChangeSupport(this);
	}
	
	// REQUETES
	
	@Override
	public boolean isFirstPlayer() {
		return isFirstPlayer;
	}
	
	@Override
	public boolean isIA() {
		return isIA;
	}
	
	@Override
	public PropertyChangeListener[] getPropertyChangeListeners() {
		return listeners.getPropertyChangeListeners();
	}
	
	@Override
	public Collection<IStartingWealth> getCards() {
		return new ArrayList<IStartingWealth>(startingWealths);
	}

	@Override
	public Collection<IActionBuilding> getActionBuildings() {
		return new HashSet<IActionBuilding>(actionBuildings);
	}

	@Override
	public Collection<IMonument> getMonuments() {
		return new HashSet<IMonument>(monuments);
	}
	
	@Override
	public int getCorn() {
		return cornManager.getCorn();
	}

	@Override
	public ITZStock getWallet() {
		return amount;
	}

	@Override
	public int getCornTiles() {
		return cornTiles;
	}

	@Override
	public int getWoodTiles() {
		return woodTiles;
	}

	@Override
	public Collection<IWorker> getTotalPawns() {
		return workersTotal;
	}

	@Override
	public Collection<IWorker> getHandPawns() {
		return workersHand;
	}
	
	@Override
	public boolean canTurnTwice() {
		return turnTwice;
	}

	@Override
	public Collection<IFarm> getFarms() {
		return cornManager.getFarms();
	}
	
	// COMMANDES
	
	@Override
	public void addScore(double score) {
		super.addScore(score);
		listeners.firePropertyChange("score", (int) (getScore() - score), (int) getScore());
	}
	
	@Override
	public void setFirstPlayer(boolean is) {
		boolean old = isFirstPlayer;
		isFirstPlayer = is;
		listeners.firePropertyChange("first", old, is);
	}
	
	@Override
	public void addPropertyChangeListener(PropertyChangeListener l) {
		listeners.addPropertyChangeListener(l);
	}
	
	@Override
	public void removePropertyChangeListener(PropertyChangeListener l) {
		listeners.removePropertyChangeListener(l);
	}

	@Override
	public void addCard(IStartingWealth c) {
		if (c == null) {
			throw new IllegalArgumentException();
		}
		startingWealths.add(c);
		listeners.firePropertyChange("cards", null, null);
	}

	@Override
	public void removeCard(IStartingWealth c) {
		if (c == null) {
			throw new IllegalArgumentException();
		}
		startingWealths.remove(c);
		listeners.firePropertyChange("cards", null, null);
	}

	@Override
	public void addBuilding(IActionBuilding b) {
		if (b == null) {
			throw new IllegalArgumentException();
		}
		actionBuildings.add(b);
		b.setOwner(this);
		listeners.firePropertyChange("buildings", null, null);
	}

	@Override
	public void addMonument(IMonument b) {
		if (b == null) {
			throw new IllegalArgumentException();
		}
		monuments.add(b);
		b.setOwner(this);
		listeners.firePropertyChange("monuments", null, null);
	}

	@Override
	public void addCorn(int i) {
		int old = getCorn();
		cornManager.addCorn(i);
		listeners.firePropertyChange("corn", old, getCorn());
	}
	
	@Override
	public void removeCorn(int i) throws NotEnoughCornException {
		int old = getCorn();
		cornManager.removeCorn(i);
		listeners.firePropertyChange("corn", old, getCorn());
	}

	@Override
	public void backPawn(IWorker p) {
		if (p == null) {
			throw new IllegalArgumentException();
		}
		if (workersHand.contains(p) || !workersTotal.contains(p)) {
			throw new IllegalStateException();
		}
		int old = workersHand.size();
		workersHand.add(p);
		listeners.firePropertyChange("pawns", old, workersHand.size());
	}

	@Override
	public void addPawn() {
		if (workersTotal.size() >= MAX_WORKERS) {
			throw new IllegalStateException();
		}
		int old = workersHand.size();
		IWorker p = new Worker(this);
		workersTotal.add(p);
		workersHand.add(p);
		listeners.firePropertyChange("pawns", old, workersHand.size());
	}
	
	@Override
	public IWorker leavePawn() {
		if (workersHand.size() == 0) {
			throw new IllegalStateException();
		}
		int old = workersHand.size();
		for (IWorker p : workersHand) {
			workersHand.remove(p);
			listeners.firePropertyChange("pawns", old, workersHand.size());
			return p;
		}
		return null;
	}
	
	@Override
	public void addCornTile() {
		++cornTiles;
		listeners.firePropertyChange("tile", cornTiles - 1, cornTiles);
	}
	
	@Override
	public void addWoodTile() {
		++woodTiles;
		listeners.firePropertyChange("tile", woodTiles - 1, woodTiles);
	}

	@Override
	public void feedWorkers(ILog log) {
		cornManager.feedWorkers(log);
	}
	
	@Override
	public void setTurnTwice(boolean can) {
		boolean old = turnTwice;
		turnTwice = can;
		listeners.firePropertyChange("turnTwice", old, turnTwice);
	}

	@Override
	public void addFarm(IFarm f) {
		cornManager.addFarm(f);
		listeners.firePropertyChange("buildings", null, null);
	}

}
